package com.kehutong.payfees.service.worker;


import com.kehutong.common.DoveClient;
import com.kehutong.common.entity.Root;
import com.kehutong.payfees.entity.*;
import com.kehutong.payfees.enums.*;
import com.kehutong.payfees.service.ChargeCallServiceImpl;
import com.kehutong.payfees.service.ChargeChooseServiceImpl;
import com.kehutong.payfees.service.receipt.PayManageServiceImpl;
import com.kehutong.payfees.util.BasicClient;
import org.coraframework.converter.Converter;
import org.coraframework.inject.Inject;
import org.coraframework.json.JSONArray;
import org.coraframework.json.JSONObject;
import org.coraframework.logger.Logger;
import org.coraframework.logger.LoggerFactory;
import org.coraframework.mvc.http.ReqMapping;
import org.coraframework.mvc.webservice.WebService;
import org.coraframework.orm.Pool;
import org.coraframework.orm.jdbc.JdbcSession;
import org.coraframework.orm.jdbc.connection.ThreadLocalCache;
import org.coraframework.util.Objects;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

@WebService("/payfees/charge/worker")
public class ChargeWorkerServiceImpl {

    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Inject
    private DoveClient doveClient;
    @Inject
    private JdbcSession jdbcSession;
    @Inject
    private BasicClient basicClient;
    @Inject
    private ChargeChooseServiceImpl chargeChooseService;
    @Inject
    private ChargeCallServiceImpl chargeCallService;

    @Inject
    private PayManageServiceImpl payManageService;

    /**
     * 获取所有企业信息
     * @return
     * @throws Exception
     */
    private JSONArray getCorps() throws Exception {
        JSONObject result = doveClient.post("/admin/service/corp/list",(http)->{});

        if (result.getIntValue("code") == 200) {
            return result.getJSONArray("data");
        }

        return null;
    }

    /**
     * 定时催缴
     */
    @ReqMapping("/call/task")
    public void callTask() throws Exception {
        JSONArray array = getCorps();
        if(Objects.nonEmpty(array)) {
            for (Object obj : array) {
                JSONObject corp = (JSONObject) obj;

                String corpId = corp.getString("id");
                if(corpId.equals(Root.ROOT_ID)){
                    continue;
                }

                ThreadLocalCache.current().setCorpId(corpId);

                try {
                    List<ChargeCallTask> tasks = jdbcSession.findArray(ChargeCallTask.class)
                            .eq("run", false)
                            .eq("callMethod", BillCallMethod.TIMING)
                            .minEq("configCallAt", LocalDateTime.now())
                            .exe();

                    for (ChargeCallTask task : tasks) {
                        chargeCallService.buildRunCallTask(task, corp.getString("id"));
                    }
                } catch (Exception e) {
                    //logger.error("callTask errror:", e);
                }
            }
        }
    }

    /**
     * 定时生成缴费账单
     * @throws Exception
     */
    @ReqMapping("/generate/bill")
    public void generateBill() throws Exception {
        JSONArray array = getCorps();

        if(Objects.nonEmpty(array)) {
            for (Object obj : array) {
                JSONObject corp = (JSONObject) obj;
                String corpId = corp.getString("id");

                if(corpId.equals(Root.ROOT_ID)){
                    continue;
                }

                ThreadLocalCache.current().setCorpId(corpId);
                try {
                    List<ChargeGenerate> generatorList = loadGenerate();
                    for (ChargeGenerate generate : generatorList) {

                        BillGenerate generator = generateBill(generate, corpId);

                        jdbcSession.insert(generator.getBillItemList());

                        List<ChargeBill> bills = generator.getBillList();
                        jdbcSession.insert(bills);

                        bills.forEach(item->{
                            try {
                                //生成pdf文件
                                payManageService.generatePdf(item,"");
                            } catch (Exception e) {
                                logger.error("订单{}，生成缴费单PDF文件失败！"+item.getId());
                            }
                        });

                        generate.setResultType(ResultType.COMPLETE);
                        jdbcSession.updateById(generate);
                    }
                } catch (Exception e) {
//                    logger.error("generateBill errror:", e);
                }
            }
        }
    }

    private BillGenerate generateBill(ChargeGenerate generate, String corpId) throws Exception {
        LocalDate beginTime;
        LocalDate endTime;
        if (generate.getGenerateType() == GenerateType.INSTRUMENT) {
            beginTime = Converter.toLocalDate(generate.getReadMonth() + "-01");
            endTime = beginTime.with(TemporalAdjusters.lastDayOfMonth());
        } else {
            beginTime = generate.getStartDate();
            endTime = generate.getEndDate();
        }


        BillGenerate generator = createGenerator(generate, corpId);
        for (JSONObject json : generator.getHouseList()) {
            generateBillForHouse(generator, generate, json, beginTime, corpId);
        }

        for (JSONObject house : generator.getHouseList()) {
            deleteOldGenerate(generate, house, beginTime, endTime);
        }


        return generator;
    }

    // 加载生成任务
    private List<ChargeGenerate> loadGenerate() {
        List<ChargeGenerate> generateList = jdbcSession.findArray(ChargeGenerate.class)
                .eq("resultType", ResultType.PROCESSING.getId())
                .minEq("exeDate", LocalDateTime.now())
                .exe();

        return generateList;
    }

    // 加载房屋
    private BillGenerate createGenerator(ChargeGenerate generate, String corpId) throws Exception {
        JSONArray array = basicClient.getHouseByIds(corpId, generate.getHouseIds());

        List<JSONObject> jsons = new ArrayList<>();
        array.forEach(obj -> {
            jsons.add((JSONObject) obj);
        });

        return BillGenerate.create(jsons);
    }

    // 删除原生成
    private void deleteOldGenerate(ChargeGenerate generate, JSONObject house,  LocalDate beginTime, LocalDate endTime) {
        List<ChargeBill> oldBills = jdbcSession.findArray(ChargeBill.class)
                .eq("houseNo", house.getString("id"))
                .eq("billDateFrom", beginTime)
                .eq("billDateTo", endTime)
                .eq("shouldPayDate", generate.getShouldPayDate())
                .eq("paidState", BillPaidState.UNPAID)
                .eq("generateType", generate.getGenerateType().getId())
                .eq("deleted", false)
                .exe();
        oldBills.forEach(oldBill->{
            oldBill.setDeleted(true);
        });
        jdbcSession.updateById(oldBills);
    }

    private void generateBillForHouse(BillGenerate generator, ChargeGenerate generate, JSONObject house, LocalDate beginTime, String corpId) throws Exception {
        ChargeBill bill = createChargeBill(corpId, generate, house);
        if (generate.getGenerateType() == GenerateType.CONVENTIONAL) {
            bill.setBillDateFrom(generate.getStartDate());
            bill.setBillDateTo(generate.getEndDate());

            // 获取所有的常规选用标准信息
            List<ChargeChoose> chooses = jdbcSession.findArray(ChargeChoose.class)
                    .eq("communityNo", generate.getCommunityNo())
                    .eq("houseNo", house.getString("id"))
                    .eq("chooseType", ChooseType.CONVENTIONAL.getId())
                    .eq("enableState", BillEnableState.ENABLE.getId())
                    .eq("deleted", false)
                    .exe();

            BigDecimal total = BigDecimal.ZERO;
            for (ChargeChoose item: chooses) {
                ChargeBillItem billItem = Pool.newInstance(ChargeBillItem.class);
                billItem.setBillNo(bill.getId());
                billItem.setFeeId(item.getFeeTypeId());
                billItem.setName(item.getFeeTypeName());
                billItem.setAmount(item.getAmount());
                billItem.setUnitPrice(item.getPrice());
                billItem.setChooseId(item.getId());

                BigDecimal subTotal = item.getTotal();

                logger.debug("========gen bill=============subTotal:{}, unit:{}, compute:{}", subTotal, item.getUnitPrice(), item.getComputeType());
                billItem.setSubTotal(new BigDecimal(subTotal.toString())
                        .setScale(Integer.valueOf(item.getUnitPrice().getId()),
                                Integer.valueOf(item.getComputeType().getId())));
                generator.addBillItem(billItem);
                total = total.add(billItem.getSubTotal());
            }
            bill.setTotal(total);
        } else {
            bill.setBillDateFrom(beginTime);
            bill.setBillDateTo(bill.getBillDateFrom().with(TemporalAdjusters.lastDayOfMonth()));

            // 获取所有的仪表选用标准信息
            List<ChargeChoose> chooses = jdbcSession.findArray(ChargeChoose.class)
                    .eq("communityNo", generate.getCommunityNo())
                    .eq("houseNo", house.getString("id"))
                    .eq("chooseType", ChooseType.INSTRUMENT.getId())
                    .eq("enableState", BillEnableState.ENABLE.getId())
                    .eq("deleted", false)
                    .exe();

            BigDecimal total = BigDecimal.ZERO;
            for (ChargeChoose item: chooses) {
                List<ChargeMonthRead> monthReads = jdbcSession.findArray(ChargeMonthRead.class)
                        .eq("communityNo", generate.getCommunityNo())
                        .eq("readMonth", generate.getReadMonth())
                        .eq("houseId",house.getString("id"))
//                        .eq("contactName", house.getString("ownerName"))
                        .eq("appType", AppType.ENTER.getId())
                        .eq("instrumentId", item.getInstrumentId())
                        .eq("deleted", false)
                        .exe();
                for (ChargeMonthRead monthRead: monthReads) {
                    ChargeBillItem billItem = Pool.newInstance(ChargeBillItem.class);
                    billItem.setMonthReadNo(monthRead.getId());
                    billItem.setBillNo(bill.getId());
                    billItem.setFeeId(item.getFeeTypeId());
                    billItem.setName(item.getFeeTypeName());
                    billItem.setLastReadNumber(monthRead.getLateRead());
                    billItem.setTheReadNumber(monthRead.getCurrentRead());
                    billItem.setAmount(monthRead.getBillNumber());
                    billItem.setUnitPrice(item.getPrice());
                    billItem.setChooseId(item.getId());

                    BigDecimal subTotal;
                    if(item.getChargeMode() == ChargeModeType.AMOUNT){
                        subTotal = java.util.Objects.nonNull(monthRead.getBillNumber()) ? monthRead.getBillNumber().multiply(item.getPrice()) : BigDecimal.ZERO.multiply(item.getPrice());
                    }else{
                        item.setAmount(monthRead.getBillNumber());
                        chargeChooseService.getTotal(item);
                        subTotal = item.getTotal();
                    }
                    //精确元角分，四舍五入
                    billItem.setSubTotal(new BigDecimal(subTotal.toString())
                            .setScale(Integer.valueOf(item.getUnitPrice().getId()),
                                    Integer.valueOf(item.getComputeType().getId())));
                    generator.addBillItem(billItem);

                    total = total.add(billItem.getSubTotal());
                }
            }
            bill.setTotal(total);

        }

        if (bill.getTotal().compareTo(BigDecimal.ZERO) == 1) {
            generator.addBill(bill);
        }
    }

    // 创建并生成账单
    private ChargeBill createChargeBill(String companyNo ,ChargeGenerate generate, JSONObject house) throws Exception {
        ChargeBill bill = Pool.newInstance(ChargeBill.class);
        bill.setGenerateNo(generate.getId());
        bill.setCommunityNo(house.getString("communityNo"));
        bill.setCommunityName(house.getString("communityName"));
        bill.setBuildingNo(house.getString("buildNo"));
        bill.setBuildingName(house.getString("buildName"));
        bill.setUnitName(house.getString("unitName"));
        bill.setFloorName(house.getString("floorName"));
        bill.setHouseName(house.getString("floorName") + house.getString("name"));
        bill.setHouseNo(house.getString("id"));

        bill.setShouldPayDate(generate.getShouldPayDate());
        bill.setEnableState(BillEnableState.ENABLE);
        bill.setGenerateType(generate.getGenerateType());

        setDepartmentNo(bill, companyNo);

        return bill;
    }

    private void setDepartmentNo(ChargeBill entity, String companyNo) throws Exception {
        JSONObject community = basicClient.getCommunityById(companyNo,
                entity.getCommunityNo());
        if(Objects.nonEmpty(community)){
            String parent_id = community.getString("parent_id");
            if(Objects.nonEmpty(parent_id)){
                entity.setDepartmentNo(parent_id);
            }
            JSONArray parent_ids = community.getJSONArray("parent_ids");
            if(Objects.nonEmpty(parent_ids)){
                List<String> departmentNos = JSONObject.parseArray(parent_ids.toJSONString(), String.class);
                entity.setDepartmentNos(departmentNos);
            }
        }
    }

}
